package new

import (
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"strings"

	"github.com/spf13/cobra"

	"gitcode.com/goinit/goinit/internal/pkg/dirx"
	"gitcode.com/goinit/goinit/internal/pkg/filex"
	"gitcode.com/goinit/goinit/internal/tpl"
	"gitcode.com/goinit/goinit/internal/tpl/model"
	"gitcode.com/goinit/goinit/internal/tpl/pkg/conf"
	"gitcode.com/goinit/goinit/internal/tpl/pkg/db"
	"gitcode.com/goinit/goinit/internal/tpl/pkg/helper"
	"gitcode.com/goinit/goinit/internal/tpl/pkg/logger"
	"gitcode.com/goinit/goinit/internal/tpl/pkg/response"
)

var cmdByProject = &cobra.Command{
	Use:     "project",
	Short:   "Create a new project framework",
	Example: "goinit new project demo",
	Run: func(cmd *cobra.Command, args []string) {
		if len(args) < 1 {
			cmd.Help()
			return
		}

		name := args[0]
		if name == "" {
			cmd.Help()
			return
		}

		if ModName == "" {
			ModName = name
		}

		if moduleName == "" {
			moduleName = "demo"
		}
		path, _ := os.Getwd()
		path = filepath.Join(path, name)

		makeProjectDirs(path, moduleName)
		touchProjectFiles(path, name, moduleName, ModName)
		touchServiceFiles(path, moduleName, ModName)
	},
}

var ModName string
var moduleName string

func init() {
	cmdByProject.Flags().StringVar(&ModName, "mod", "github.com/xxx/xxx", "Module path in go.mod file")
	cmdByProject.PersistentFlags().StringVarP(&moduleName, "module", "m", "demo", "module name")
}

func makeProjectDirs(path, serverName string) {
	dirs := []string{
		filepath.Join(path, "cmd", serverName),
		filepath.Join(path, "pkg"),
		filepath.Join(path, "api"),
		filepath.Join(path, "web"),
		filepath.Join(path, "script"),
		filepath.Join(path, "config"),
		filepath.Join(path, "test"),

		filepath.Join(path, "internal", "pkg"),
		filepath.Join(path, "internal", "model"),
		filepath.Join(path, "internal", "app", serverName, "handler"),
		filepath.Join(path, "internal", "app", serverName, "migrate"),
		filepath.Join(path, "internal", "app", serverName, "server"),
		filepath.Join(path, "internal", "app", serverName, "service"),
		filepath.Join(path, "internal", "app", serverName, "repository"),
	}

	for _, d := range dirs {
		if err := dirx.Create(d); err != nil {
			fmt.Printf("Failed to create directory %s: %s\n", d, err)
			return
		}
	}
}

func touchProjectFiles(path, projectName, serverName, modName string) {
	value := map[string]string{
		"ProjectName":    projectName,
		"ServerName":     serverName,
		"ModName":        modName,
		"GoVersion":      strings.Replace(runtime.Version(), "go", "", 1),
		"ModelName":      "user",
		"HandlerName":    "user",
		"ServiceName":    "user",
		"RepositoryName": "user",
	}

	files := map[string]string{
		filepath.Join(path, "go.mod"):                                     string(tpl.Mod),
		filepath.Join(path, "README.md"):                                  string(tpl.README),
		filepath.Join(path, "config", "config.yaml"):                      string(conf.Value),
		filepath.Join(path, "internal", "pkg", "db", "database.go"):       string(db.Db),
		filepath.Join(path, "internal", "pkg", "log", "logger.go"):        string(logger.Logger),
		filepath.Join(path, "internal", "pkg", "log", "gorm.go"):          string(logger.Gorm),
		filepath.Join(path, "internal", "pkg", "conf", "conf.go"):         string(conf.Conf),
		filepath.Join(path, "internal", "pkg", "response", "response.go"): string(response.Response),
		filepath.Join(path, "internal", "pkg", "response", "error.go"):    string(response.Error),
		filepath.Join(path, "internal", "pkg", "sid", "sid.go"):           string(helper.SID),
		filepath.Join(path, "internal", "pkg", "uuid", "uuid.go"):         string(helper.UUID),
		filepath.Join(path, "internal", "pkg", "md5", "md5.go"):           string(helper.Md5),
		filepath.Join(path, "internal", "model", "pages.go"):              string(model.Pages),
		filepath.Join(path, "internal", "model", "user.go"):               string(model.Model),
	}

	for f, content := range files {
		filex.Create(f, content, value)
	}
}
